package com.yitiao.service;

import com.yitiao.entities.User;
import com.yitiao.mapper.UserMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private RedisTemplate<String, User> redisTemplate;

    private static final String CACHE_KEY_USER = "user_";

    // 先插入数据库,再存入redis
    public void addUser(User user) {
        int i = userMapper.insert(user);
        if (i > 0) {
            User cacheUser = userMapper.selectById(user.getId());
            redisTemplate.opsForValue().set(CACHE_KEY_USER+cacheUser.getId(),user);
        }
    }

    public void deleteUser(Integer id){
        int i = userMapper.deleteById(id);
        if (i>0){
            redisTemplate.delete(CACHE_KEY_USER+id);
        }
    }

    public void updateUser(User user) {
        int i = userMapper.updateById(user);
        if (i>0){
            User cacheUser = userMapper.selectById(user.getId());
            redisTemplate.opsForValue().set(CACHE_KEY_USER+cacheUser.getId(),user);
        }
    }

    public User selectById(Integer id){
        // 缓存击穿
        User user = redisTemplate.opsForValue().get(CACHE_KEY_USER + id);
        if (user==null){
            synchronized (UserService.class){
                // 二次查询缓存，判断前面上一个线程是否已经set
                User secondUser = redisTemplate.opsForValue().get(CACHE_KEY_USER + id);
                if (secondUser==null){
                    User sqlUser = userMapper.selectById(id);
                    if (sqlUser!=null){
                        // 更新数据库
                        redisTemplate.opsForValue().set(CACHE_KEY_USER+id,sqlUser);
                        return sqlUser;
                    }else {
                        // 缓存空值，解决缓存穿透
                        User nullUser = new User();
                        redisTemplate.opsForValue().set(CACHE_KEY_USER+id,nullUser);
                        return nullUser;
                    }
                }
                return secondUser;
            }
        }
        return user;
    }

    // 以上方案锁力度过重，可切换为分布式锁，也可用布隆过滤器。
}
